package easier.fast.page.pull;

import android.content.Context;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.ejlchina.okhttps.HttpResult.State;
import com.ejlchina.okhttps.OkHttpsException;
import com.scwang.smart.refresh.layout.SmartRefreshLayout;
import com.scwang.smart.refresh.layout.api.RefreshLayout;
import com.scwang.smart.refresh.layout.listener.OnRefreshListener;
import easier.fast.service.observer.BaseLifeObserver;
import easier.recycler.MultiTypeAdapter;
import easier.recycler.MultiTypeAdapter.TypeViewHolder;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.disposables.Disposable;
import java.net.ConnectException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 主要功能:统一显示网络异常界面,空数据界面
 * 一个辅助类,可以下拉刷新,发送请求,然后显示界面,或者显示空数据界面,网络异常界面
 *
 * @param <T> 数据类型
 */
public abstract class RefreshRecyclerManager< T > {

    private static final int state_data = 1;
    private static final int state_net_error = 2;
    private static final int state_no_data = 3;

    protected SmartRefreshLayout mRefresh;
    protected RecyclerView mRecycler;
    protected MultiTypeAdapter mAdapter;

    protected Lifecycle mLifecycle;

    /**
     * 记录是否正在请求
     */
    private Disposable mD;
    protected T mData;
    protected int mCurrentState;

    public RefreshRecyclerManager( SmartRefreshLayout refresh, RecyclerView recycler, Lifecycle lifecycle ) {

        mRefresh = refresh;
        mRecycler = recycler;

        mLifecycle = lifecycle;

        initViewAction();
    }

    protected void initViewAction() {

        mRefresh.setOnRefreshListener( new OnRefreshListener() {
            @Override
            public void onRefresh( @NonNull RefreshLayout refreshLayout ) {

                getData( mRecycler.getContext(), mLifecycle );
            }
        } );
        mRefresh.setEnableRefresh( true );
        mRefresh.setEnableLoadMore( false );
        mRefresh.setEnableAutoLoadMore( false );

        mRecycler.setLayoutManager( new LinearLayoutManager( mRecycler.getContext() ) );
        mAdapter = new MultiTypeAdapter();
        mRecycler.setAdapter( mAdapter );
    }

    /**
     * 开始加载数据
     */
    public void start( int delayMillis ) {

        /* SmartRefreshLayout bug 需要延时300ms,才能触发刷新 */
        if ( delayMillis > 0 ) {
            mRefresh.postDelayed( new Runnable() {
                @Override
                public void run() {

                    mRefresh.autoRefresh();
                }
            }, Math.max( delayMillis, 300 ) );
        } else {
            mRefresh.post( new Runnable() {
                @Override
                public void run() {

                    mRefresh.autoRefresh();
                }
            } );
        }
    }

    /**
     * @return 创建数据请求
     */
    protected abstract Observable< T > createRequest( Context context );

    /**
     * @param context context
     *
     * @return 创建内容布局
     */
    protected abstract List< TypeViewHolder > createContentView( Context context, T t );

    /**
     * @param context 创建网络异常布局
     *
     * @return 网络异常布局
     */
    protected abstract TypeViewHolder createNetErrorView( Context context );

    /**
     * @param context 创建没有数据界面
     *
     * @return 没有数据界面
     */
    protected abstract TypeViewHolder createNoDataView( Context context );

    protected void cancelRequest() {

        if ( mD != null ) {
            mD.dispose();
            mD = null;
        }
        mRefresh.finishRefresh();
    }

    /**
     * 请求数据
     */
    protected void getData( Context context, Lifecycle lifecycle ) {

        /* 正在请求中 */
        if ( mD != null ) {
            return;
        }

        createRequest( context )
            .subscribe( new BaseLifeObserver< T >( context, lifecycle ) {
                @Override
                public void onSubscribe( @NonNull Disposable d ) {

                    super.onSubscribe( d );
                    mD = d;
                }

                @Override
                public void onNext( @NonNull T s ) {

                    super.onNext( s );

                    boolean b = !Objects.equals( s, mData );
                    if ( mCurrentState != state_data || b ) {
                        mCurrentState = state_data;
                        List< TypeViewHolder > holders = null;
                        try {
                            holders = createContentView( mRefresh.getContext(), s );
                        } catch ( Exception e ) {
                            holders = new ArrayList<>();
                        }
                        List< TypeViewHolder > contentView = holders;
                        mAdapter.updateViewHolders( contentView );
                    }

                    mData = s;
                    cancelRequest();
                }

                @Override
                public void onError( @NonNull Throwable e ) {

                    super.onError( e );

                    boolean netError = isConnectError( e );
                    if ( netError ) {

                        if ( mCurrentState != state_net_error ) {
                            mCurrentState = state_net_error;
                            List< TypeViewHolder > list = new ArrayList<>();
                            list.add( createNetErrorView( context ) );
                            mAdapter.updateViewHolders( list );
                        }

                    } else {

                        if ( mCurrentState != state_no_data ) {
                            mCurrentState = state_no_data;
                            List< TypeViewHolder > list = new ArrayList<>();
                            list.add( createNoDataView( context ) );
                            mAdapter.updateViewHolders( list );
                        }
                    }

                    mData = null;
                    cancelRequest();
                }

                @Override
                public void onComplete() {

                    super.onComplete();
                    cancelRequest();
                }
            } );
    }

    public static boolean isConnectError( Throwable e ) {

        boolean netError = false;
        if ( e instanceof ConnectException ) {
            netError = true;
        } else if ( e instanceof OkHttpsException ) {
            State state = ((OkHttpsException) e).getState();
            if ( state == State.TIMEOUT || state == State.NETWORK_ERROR ) {
                netError = true;
            }
        }
        return netError;
    }
}

